Skip to content

Conversation

@RobinMalfait
Copy link
Contributor

This PR fixes an issue where an Error: Unexpected undefined is thrown.

For context, we use @tanstack/virtual-react in Headless UI for our Combobox component. The Combobox component can be used to show a big list of items and you can also filter the list by typing in the ComboboxInput. This is also where the issue exists, if you type something and you have a match, then we will scroll to that position using the virtualizer.scrollToIndex(activeOptionIndex) API. If nothing matches, then we don't scroll, but our internal list of items will be empty.

We use the useVirtualizer hook like this:

let virtualizer = useVirtualizer({
  enabled: options.length !== 0,
  count: options.length,
  // …
})

This therefore means that the count will be 0 and the enabled will become false.

We tracked down the issue to the few lines of code changed in the PR.

Before this code runs, we already verify that the offset for a specific index exists. If this is not the case, then we bail by just using a return.

However, before we changed the code, the lines changed in this PR assumed that the same conditions hold true. However, this is also running in a setTimeout which means that values could have changed in the meantime (which can happen due to filtering we mentioned above which causes re-renders).

Another issue is that because of the setTimeout, you can't even catch this error in user land.

So to fix it, once we check if the offset is still available inside of the setTimeout, we will also just silently bail if it results in undefined.

Fixes: #879

Before the this code runs, we already verify that the offset for a
specific index exists. If this is not the case, then we bail by just
using a `return`

However, the code changed in this commit then assumes that the same
conditions hold true. However, this is also running in a `setTimeout`
which means that values could have changed in the meantime (which can
happen due to React re-renders).

In our particular issue in Headless UI, it's because somebody is
filtering a Combobox while typing. This in turn changes the `enabled`
and `count`
from the `useVirtualizer` options.

How we use it in Headless UI:
```
let virtualizer = useVirtualizer({
  enabled: options.length !== 0,
  count: options.length,
  // …
})
```

Another issue is that because of the `setTimeout`, you can't even catch
this error in user land.

So to fix it, once we check if the offset is still available inside of
the `setTimeout`, we will also just silently bail if it results in
`undefined`.
@changeset-bot
Copy link

changeset-bot bot commented May 20, 2025

🦋 Changeset detected

Latest commit: 257fa0d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@tanstack/virtual-core Patch
@tanstack/angular-virtual Patch
@tanstack/lit-virtual Patch
@tanstack/react-virtual Patch
@tanstack/solid-virtual Patch
@tanstack/svelte-virtual Patch
@tanstack/vue-virtual Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nx-cloud
Copy link

nx-cloud bot commented May 20, 2025

View your CI Pipeline Execution ↗ for commit 257fa0d.

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 2m 25s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 17s View ↗

☁️ Nx Cloud last updated this comment at 2025-05-20 10:16:10 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented May 20, 2025

More templates

@tanstack/angular-virtual

npm i https://pkg.pr.new/@tanstack/angular-virtual@1004

@tanstack/lit-virtual

npm i https://pkg.pr.new/@tanstack/lit-virtual@1004

@tanstack/react-virtual

npm i https://pkg.pr.new/@tanstack/react-virtual@1004

@tanstack/solid-virtual

npm i https://pkg.pr.new/@tanstack/solid-virtual@1004

@tanstack/svelte-virtual

npm i https://pkg.pr.new/@tanstack/svelte-virtual@1004

@tanstack/vue-virtual

npm i https://pkg.pr.new/@tanstack/vue-virtual@1004

@tanstack/virtual-core

npm i https://pkg.pr.new/@tanstack/virtual-core@1004

commit: 257fa0d

@piecyk piecyk changed the title fix(virtual-core): fix Error: Unexpected undefined fix(virtual-core): fix Error: Unexpected undefined in scrollToIndex May 20, 2025
@piecyk piecyk merged commit 9e33cdb into TanStack:main May 20, 2025
4 checks passed
@piecyk
Copy link
Collaborator

piecyk commented May 20, 2025

Thanks @RobinMalfait

@github-actions github-actions bot mentioned this pull request May 20, 2025
RobinMalfait added a commit to tailwindlabs/headlessui that referenced this pull request May 20, 2025
This PR fixes an issue with the `Combobox` component when using the
`virtual` mode.

We recently already fixed this issue
(#3678) by applying a
patch on the `@tanstack/virtual-core` package. But this was only applied
in cjs builds, not in the esm builds.

Instead of trying to fix it in our build process, we decided to just fix
it upstream (TanStack/virtual#1004) and this PR
bumps the version of `@tanstack/virtual-core` to the latest version
(which includes the fix).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected undefined in Virtualizer.scrollToIndex

2 participants